package com.gitee.wsl.time.wheel

import com.gitee.wsl.coroutines.atomic.newCondition
import com.gitee.wsl.concurrent.exception.InterruptedException
import com.gitee.wsl.ext.base.currentTimeMillis
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.concurrent.Volatile

open class ReferenceQueue<T> {
    private class NullImp<S> : ReferenceQueue<S>() {
        override suspend fun enqueue(r: Reference<out S>): Boolean {
            return false
        }
    }

    private val lock = Mutex()
    private val aWaiter = lock.newCondition()

    //队列的首部
    @Volatile
    private var head: Reference<out T>? = null

    //队列的长度
    private var queueLength: Long = 0

    //入队，由Reference的ReferenceHandler线程调用
    open suspend fun enqueue(r: Reference<out T>): Boolean {
        lock.withLock {
            //获取r的queue属性，检查有没有指定引用队列或已经入队或出队
            val queue: ReferenceQueue<*>? = r.queue
            if ((queue === NULL) || (queue === ENQUEUED)) return false
            require(queue === this)
            //标记为已经入队
            r.queue = ENQUEUED as ReferenceQueue<in T>?
            //如果head为null，则将这个Reference作为head
            r.next = if (head == null) r else head
            //将r作为head，实际上是一个栈?
            head = r
            //队列长度加1
            queueLength++
            //if (r is FinalReference) sun.misc.VM.addFinalRefCount(1)
            //唤醒调用remove的线程
            aWaiter.signalAll()
            //aWaiter.notifyAll()
            return true
        }
    }

    //出队操作，如果没有元素直接返回null
    suspend fun poll(): Reference<out T>? {
        if (head == null) return null
        lock.withLock {
            return reallyPoll()
        }
    }

    private fun reallyPoll(): Reference<out T>? {
        val r: Reference<out T>? = head
        if (r != null) {
            //将队列中下一个Reference赋给head
            head = (if (r.next === r) null else r.next) as Reference<out T>?
            //标记为NULL表示已出队
            r.queue = NULL as ReferenceQueue<in T>?
            //将next设为r(即自身)
            r.next = r
            //队列长度减1
            queueLength--
            //if (r is FinalReference) addFinalRefCount(-1)
            return r
        }
        return null
    }

    //出队，如果没有元素该线程会阻塞到有元素返回
    @Throws(InterruptedException::class)
    suspend fun remove(): Reference<out T>? {
        return remove(0)
    }

    //出队，如果没有元素那么最多等待timeOut毫秒直到超时或者有元素入队
    @Throws(IllegalArgumentException::class,InterruptedException::class)
    suspend fun remove(timeout: Long): Reference<out T>? {
        var timeout = timeout
        require(timeout >= 0) { "Negative timeout value" }
        lock.withLock {
            var r: Reference<out T>? = reallyPoll()
            if (r != null) return r
            var start: Long = if (timeout == 0L) 0 else currentTimeMillis
            while (true) {
                //最多等待timeOut毫秒
                aWaiter.await(timeout)
                r = reallyPoll()
                if (r != null) return r
                if (timeout != 0L) {
                    val end: Long = currentTimeMillis
                    timeout -= end - start
                    if (timeout <= 0) return null
                    start = end
                }
            }
        }
    }

    companion object {
        //当Reference入队前，其成员变量queue为NULL，入队后，其成员变量为ENQUEUED
        var NULL: ReferenceQueue<Any> = NullImp<Any>()
        var ENQUEUED: ReferenceQueue<Any> = NullImp<Any>()
    }
}